//
//  LineGraphView.m
//  MindView
//
//  Created by NeuroSky on 10/13/11.
//  Copyright 2012. All rights reserved.
//

#import "LineGraphView.h"

@implementation LineGraphView

@synthesize backgroundColor;
@synthesize lineColor;
@synthesize cursorColor;
@synthesize cursorEnabled;
@synthesize addTo;
@synthesize tagert;
@synthesize scaler;
@synthesize xAxisMax;


float numberOfBigBlocks;
float numberOfSmallBlocks;
float bigBlockSize;
float smallBlockSize;
float lineOffset;
float gridScale;


- (id)initWithCoder:(NSCoder *)aDecoder {
    if(self = [super initWithCoder:aDecoder]) {
        [self initialize];
    }    
    return self;
}

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self initialize];
    }    
    return self;
}

- (void)initialize {
    
    xAxisMin = 0;    //seconds
    xAxisMax = 6;    //seconds
    yAxisMin = -2048;
    yAxisMax = 2048;
    dataRate = 128;  //Hz

    decimateCount = 0;
    averageCount = 0;
    offsetRemovalEnabled = NO;
    lineOffset = 1;
    
    invertSignal = YES;
    
    data = [[NSMutableArray alloc] initWithCapacity:(dataRate * xAxisMax)];
    
    index = 0;

    scaler = CARDIO_SCALER;
    
    dataLock = [[NSLock alloc] init];
       
    redraw = [[NSThread alloc] initWithTarget:self selector:@selector(redrawThread) object:nil];
    [redraw start];
    
    if(backgroundColor == nil) {
        backgroundColor = [UIColor clearColor];
        self.backgroundColor = backgroundColor;
    }
    
    lineColor = [UIColor blackColor];
    cursorColor = [UIColor redColor];
    
    cursorEnabled = YES;
    gridEnabled = YES;
    touchEnabled = NO;
    
    if(touchEnabled) {
        pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingerPinch:)];
        [self addGestureRecognizer:pinch];
        taptap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap)];
        taptap.numberOfTapsRequired = 2;
        [self addGestureRecognizer:taptap];
    }
    
    ECGBufferCounter = 0;
    
    NSURL * url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/BeepLow.aiff", [[NSBundle mainBundle] resourcePath]]];
    NSError *error;
    audio = [[AVAudioPlayer alloc] initWithContentsOfURL:url
                                                   error:&error];
}

- (void)dealloc {
    free(ECGbuffer);
    free(filteredPoint);
}

- (void)drawRect:(CGRect)clientRect {

    if(data.count > 1) {
        
        if(gridEnabled) {
            
            numberOfBigBlocks = (xAxisMax / 0.2);
            numberOfSmallBlocks = numberOfBigBlocks * 5;
            bigBlockSize = (self.frame.size.width / numberOfBigBlocks);
            smallBlockSize = bigBlockSize / 5;
            gridScale = scaler - CARDIO_SCALER;
            
            // Small Blocks
            smallGrid = [UIBezierPath bezierPath];
            [smallGrid removeAllPoints];
            [smallGrid setLineWidth:0.2];
            
            // Vertical lines
            [smallGrid moveToPoint:[self point2PixelsWithXValue:0.0 yValue:yAxisMax]];
            for (int i = 0; i < numberOfSmallBlocks; i++) {
                [smallGrid addLineToPoint:CGPointMake((i * smallBlockSize), yAxisMin)];
                [smallGrid moveToPoint:CGPointMake((i + 1) * smallBlockSize, yAxisMax)];
            }
            
            // Horizontal lines
            [smallGrid moveToPoint:[self point2PixelsWithXValue:0.0 yValue:yAxisMax + lineOffset]];
            for (int i = 0; i < numberOfSmallBlocks; i++) {
                
                [smallGrid addLineToPoint:CGPointMake(xAxisMin, (i * smallBlockSize) + lineOffset)];                
                [smallGrid moveToPoint:CGPointMake(self.frame.size.width, ((i + 1) * smallBlockSize) + lineOffset)];
            }
            
            [[UIColor redColor] set];
            [smallGrid stroke];
            
            // Large blocks
            
            grid = [UIBezierPath bezierPath];
            [grid removeAllPoints];
            [grid setLineWidth:0.3];
            
            // Vertical lines
            [grid moveToPoint:[self point2PixelsWithXValue:0.0 yValue:yAxisMax]];
            for (int i = 0; i < numberOfBigBlocks; i++) {
                [grid addLineToPoint:CGPointMake((i * bigBlockSize), yAxisMin)];
                [grid moveToPoint:CGPointMake((i + 1) * bigBlockSize, yAxisMax)];
            }
            
            // Horizontal lines
            [grid moveToPoint:[self point2PixelsWithXValue:0.0 yValue:yAxisMax + lineOffset]];
            for (int i = 0; i < numberOfBigBlocks; i++) {

                [grid addLineToPoint:CGPointMake(xAxisMin, (i * bigBlockSize) + lineOffset)];
                
                [grid moveToPoint:CGPointMake(self.frame.size.width, ((i + 1) * bigBlockSize) + lineOffset)];
            }
            
            [[UIColor redColor] set];
            [grid stroke];
        }
        
        path = [UIBezierPath bezierPath];
        [path removeAllPoints];

        [path setLineWidth:LINE_WIDTH];
        [path moveToPoint:CGPointMake(0, clientRect.size.height/2)];
        
        for(int i = 0; i < data.count; i++) {
            
            NSNumber *tempValue = (NSNumber *)[data objectAtIndex:i]; 
            
            CGPoint tempPixel = [self point2PixelsWithXValue:i
                                                      yValue:([tempValue doubleValue] * scaler)];
            [path addLineToPoint:tempPixel];
        }
        
        [lineColor set];
        [path stroke];
        if(cursorEnabled) {
            cursor = [UIBezierPath bezierPath];
            [cursor removeAllPoints];
            
            [cursor setLineWidth:2];
            [cursor moveToPoint:[self point2PixelsWithXValue:index yValue:yAxisMax]];
            [cursor addLineToPoint:[self point2PixelsWithXValue:index yValue:yAxisMin]];
            [cursorColor set];
            [cursor stroke];
        }
        newData = NO;
    }    
}

- (CGPoint)point2PixelsWithXValue:(double) xValue yValue:(double) yValue {
    CGPoint temp = {0, 0};
    
    temp.x = xValue * self.frame.size.width / (dataRate / DECIMATE * xAxisMax);
    temp.y = ((yValue - yAxisMin) / (yAxisMax - yAxisMin) * self.frame.size.height);
    
    if(!invertSignal) temp.y = self.bounds.size.height - temp.y;
    //NSLog(@"pixel: %f, %f", temp.x, temp.y);
    return temp;
}

- (void)addPoint {
    int f = 10;
    double x = index++ / dataRate;
    double y = sin(2 * M_PI * x * f);
    NSValue *temp = [NSValue valueWithCGPoint:CGPointMake(x,y)];
    
    [dataLock lock];
    [data addObject:temp];
    if(data.count > xAxisMax * dataRate) {
        [data removeObjectAtIndex:0];
    }
    [dataLock unlock];
}

- (double)addValue:(double) value {
    
    double newValue = value * -1;
    decimateCount++;
    if (decimateCount < DECIMATE) {
        return newValue;
    } else {
        decimateCount = 0;
    }
    if (index > dataRate / DECIMATE * xAxisMax - 1) {
        
        //
        //cursorEnabled=YES;
        
        if (cursorEnabled) {
            //NSLog(@"cursorEnabled======YES");
        }
        else{
            //NSLog(@"cursorEnabled======NO");
        }
        
//        [self.tagert performSelector:addTo withObject:nil];
        index = 0;
    }  
    
    if(offsetRemovalEnabled){
        if(averageCount < AVERAGE_COUNT) averageCount++;
//        [self.tagert performSelector:addTo withObject:nil];

        average = (average*(averageCount - 1) + newValue)/averageCount;
    }else {
        average = 0;
    }
    
    [dataLock lock];
    
    if(data.count < dataRate / DECIMATE * xAxisMax) {
        [data insertObject:[NSNumber numberWithDouble:newValue - average] atIndex:index];
    }else {
        [data replaceObjectAtIndex:index withObject:[NSNumber numberWithDouble:newValue - average] ];
    }

    //NSLog(@"data count: %d", data.count);   

    index++;
    [dataLock unlock];
    newData = YES;
    
    return newValue;
}

- (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer {
    scaler += recognizer.scale - 1;
    if(scaler < 0.4)
        scaler = 0.4;
    else if (scaler > 5)
        scaler = 5;
    //NSLog(@"Pinch scale: %f", scaler);
}

- (void)doubleTap {
    scaler = 1;
}

- (void)redrawThread {
    while (true) {
        if (newData) {
            [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
        }
        [NSThread sleepForTimeInterval:0.033];
    }
    
}

-(void)cleardata{
    
    [dataLock lock];
    [data removeAllObjects];
    decimateCount = 0;
    averageCount = 0;
    index = 0;
    [dataLock unlock];    
}

- (void)playBeep {
    [audio play];    
}



@end
